package slash.world;

import java.util.*;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.*;
import org.newdawn.slick.tiled.TiledMap;
import org.newdawn.slick.util.Log;

import slash.constants.Globals;
import slash.entities.*;

public class Map {
	
	private TiledMap map;
	private ArrayList<MapLayer> layers;
	/** width of a tile */
	private int tileWidth;
	/** height of a tile */
	private int tileHeight;
	private int height, width;
	/** map name and key in world hasmap */
	private String name;

	/** path of the tiledmap */
	private String mapPath;
	
	/**
	 * Creates a new map from a path
	 * and gives it a name.
	 *Par: mapname, mapfilepath
	 */
	public Map(String name, String path){
		layers = new ArrayList<MapLayer>();
		this.name = name;
		this.mapPath = path;
		
		try {
			map = new TiledMap(path);
		} catch (SlickException e) {
			/* couldn't get tiledmap at string location */
			Log.error("Couldn't get tiledmap from path string", e);
		}
		
		setBounds();
		loadLayers();
	}
	
	/**
	 * Loads map objects into map layers for better managing
	 */
	public void loadLayers(){
		CollisionLayer layerC = new CollisionLayer();
		EntityLayer layerE = new EntityLayer();
		
		int objectLayersCount = map.getObjectGroupCount();// number of object-layers in tiled map
        for (int objectLayerIndex = 0; objectLayerIndex < objectLayersCount; objectLayerIndex++) {// object layer index
                int objectsInGroup = map.getObjectCount(objectLayerIndex);// number of objects in layer
                for (int objectID = 0; objectID < objectsInGroup; objectID++) {// object ID in object layer
                        int x = map.getObjectX(objectLayerIndex, objectID);// posX of object
                        int y = map.getObjectY(objectLayerIndex, objectID);// posY of object
                        int width = map.getObjectWidth(objectLayerIndex, objectID);// width of object
                        int height = map.getObjectHeight(objectLayerIndex, objectID);// height of object
                        
                        /* adds collision-type objects to collision layer*/
                        if(map.getObjectType(objectLayerIndex, objectID).equals(Globals.OBJECT_COLLISION)){
                        	Shape shape = new Rectangle(x,y,width,height);// rectangle collision mask shape
                        	CollisionBox box = new CollisionBox(x,y,shape);
                        	layerC.addCollisionBox(box);// adds collision box to collision layer
                        }
                }
        }
        
        layers.add(layerC);
        layers.add(layerE);
	}
	
	/**
	 * Updates map
	 * @param time
	 */
	public void update(GameContainer container, int time){
		for(MapLayer layer : layers){
			layer.update(container, time);
		}
	}
	
	/**
	 * Renders map and all the maplayers
	 * Par: graphics
	 * @param container 
	 */
	public void render(Graphics g){
		this.map.render(0, 0);//renders tiled map
		renderLayers(g);//renders entities in layers
	}
	
	/**
	 * Renders map layers
	 * Par: graphics
	 */
	public void renderLayers(Graphics g){
		for(MapLayer layer : layers){
			layer.render(g);
		}
	}
	
	/**
	 * Returns the TiledMap for the map
	 */
	public TiledMap getMap() {
		return map;
	}
	
	public ArrayList<MapLayer> getMapLayers(){
		return this.layers;
	}
	
	public MapLayer getLayer(int index){
		return layers.get(index);
	}
	
	public EntityLayer getEntityLayer(){
		return (EntityLayer) layers.get(1);
	}
	
	private void setBounds(){
		tileWidth = map.getWidth();
		tileHeight = map.getHeight();
		height = tileHeight * map.getTileHeight();
		width = tileWidth * map.getTileWidth();
	}
	
	/**
	 * Returns arraylist containing all colidable entities
	 * on the maps
	 * @return
	 */
	public ArrayList<AbstractEntity> getCollidableObjects(){
		ArrayList<AbstractEntity> elist = new ArrayList<AbstractEntity>();
		
		for(MapLayer layer : layers){
			for(int x = 0; x < layer.getObjects().size(); x++){
				elist.add(layer.getObjects().get(x));
			}
		}
		
		return elist;
	}

	public void setMap(TiledMap map) {
		this.map = map;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}

	public int getWidth() {
		return width;
	}

	public void setWidth(int width) {
		this.width = width;
	}
	
	/**
	 * Returns the name
	 * of the map
	 * @return
	 */
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	/**
	 * Returns the map path of the
	 * tiled map file
	 */
	public String getMapPath() {
		return mapPath;
	}
	
	/**
	 * Sets the map path of the
	 * tiled map
	 * @param mapPath
	 */
	public void setMapPath(String mapPath) {
		this.mapPath = mapPath;
	}

}
